Aller au contenu principal

Utilisation de Symfony UX

Utiliser un composant Symfony UX pour créer des graphiques avec ux-chartjs

Notions théoriques

Qu'est-ce que ux-chartjs ?

symfony/ux-chartjs est un composant officiel de Symfony UX qui permet de créer des graphiques interactifs dans une application Symfony, en écrivant uniquement du code PHP et Twig. Il encapsule la bibliothèque JavaScript Chart.js — l'une des plus populaires au monde pour la visualisation de données — et l'expose via une API PHP simple et cohérente avec l'écosystème Symfony.

Sans ux-chartjs, intégrer Chart.js dans une application Symfony nécessiterait d'écrire manuellement du JavaScript, de gérer les données côté client, et de maintenir une synchronisation entre le backend PHP et le frontend JS. Avec ux-chartjs, tout se fait côté PHP : les données, le type de graphique, les couleurs, les options — et Chart.js s'occupe du rendu automatiquement dans le navigateur.

Les types de graphiques disponibles

Chart.js, et donc ux-chartjs, supporte plusieurs types de graphiques, tous accessibles via des constantes PHP :

Constante PHPType de graphique
Chart::TYPE_BARBarres verticales
Chart::TYPE_LINECourbes / lignes
Chart::TYPE_PIECamembert
Chart::TYPE_DOUGHNUTAnneau
Chart::TYPE_RADARRadar
Chart::TYPE_POLAR_AREAAires polaires
Chart::TYPE_BUBBLEBulles
Chart::TYPE_SCATTERNuage de points
astuce

Pour une première utilisation, les types BAR (barres) et LINE (courbes) sont les plus simples à comprendre et à configurer. Ce sont aussi les plus courants dans les applications de gestion.

La structure des données d'un graphique

La structure des données d'un graphique Chart.js

Tout graphique Chart.js repose sur une structure de données précise. En PHP avec ux-chartjs, cette structure se construit via les méthodes setData() et setOptions() de l'objet Chart.

Les données (setData) se composent de :

  • labels : un tableau de chaînes de caractères qui constituent les étiquettes de l'axe X (ou les légendes pour un camembert). Exemple : ['Janvier', 'Février', 'Mars']
  • datasets : un tableau de jeux de données. Chaque dataset représente une série de valeurs à afficher. Un graphique peut en avoir plusieurs (exemple : ventes 2023 et ventes 2024 superposées).

Chaque dataset contient :

[
'label' => 'Ventes 2024', // Légende de la série
'data' => [120, 85, 200, 160], // Valeurs numériques
'backgroundColor' => 'rgba(54, 162, 235, 0.5)', // Couleur de fond
'borderColor' => 'rgb(54, 162, 235)', // Couleur de bordure
'borderWidth' => 1, // Épaisseur de bordure
]
info

Les couleurs dans Chart.js s'expriment en rgba (rouge, vert, bleu, opacité) ou en rgb. L'opacité (dernier paramètre de rgba) va de 0 (transparent) à 1 (opaque). Pour les barres, une opacité de 0.5 à 0.8 est souvent esthétique.

Les options de configuration

Les options de configuration avec setOptions

La méthode setOptions() permet de personnaliser le comportement et l'apparence du graphique. Elle accepte un tableau PHP qui correspond aux options Chart.js :

$chart->setOptions([
'scales' => [
'y' => [
'beginAtZero' => true, // L'axe Y commence à 0
],
],
'plugins' => [
'legend' => [
'position' => 'top', // Position de la légende
],
'title' => [
'display' => true,
'text' => 'Titre du graphique',
],
],
'responsive' => true, // Le graphique s'adapte à la taille du conteneur
]);
remarque

Toutes les options disponibles dans Chart.js sont utilisables dans setOptions(). La documentation officielle de Chart.js (https://www.chartjs.org/docs/latest/) liste l'intégralité des options par type de graphique.

Le flux complet : de PHP au navigateur

Voici comment ux-chartjs fonctionne en coulisses, de la création du graphique en PHP jusqu'à son affichage dans le navigateur :

1. Dans le contrôleur PHP On injecte ChartBuilderInterface et on crée un objet Chart avec ses données et ses options.

2. Dans le template Twig On appelle la fonction render_chart(chart) qui génère une balise <canvas> HTML avec les données sérialisées en JSON dans un attribut data-*.

3. Dans le navigateur Stimulus détecte la balise <canvas> via l'attribut data-controller, lit les données JSON, et instancie Chart.js pour afficher le graphique interactif.

PHP (ChartBuilder)
→ Objet Chart (données + options)
→ Twig render_chart()
→ HTML <canvas data-*="...JSON...">
→ Stimulus controller.js
→ Chart.js (rendu visuel)
attention

Pour que render_chart() soit disponible dans Twig, le composant symfony/ux-chartjs doit être installé et la balise {{ importmap('app') }} doit être présente dans base.html.twig. Sans cette balise, le contrôleur Stimulus ne se charge pas et le graphique n'apparaît pas.

L'injection de dépendances

L'injection de dépendances avec ChartBuilderInterface

En Symfony, on ne crée pas d'objets Chart directement avec new Chart(). On passe par une interface : ChartBuilderInterface. Cette interface est injectée automatiquement par le conteneur de services de Symfony dans le constructeur du contrôleur ou directement en paramètre de la méthode du contrôleur.

use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

class StatistiqueController extends AbstractController
{
#[Route('/stats', name: 'app_stats')]
public function index(ChartBuilderInterface $chartBuilder): Response
{
$chart = $chartBuilder->createChart(Chart::TYPE_BAR);
// ...
return $this->render('statistique/index.html.twig', [
'chart' => $chart,
]);
}
}
astuce

L'utilisation d'une interface (ChartBuilderInterface) plutôt que d'une classe concrète est une bonne pratique Symfony. Cela permet de remplacer l'implémentation sans modifier le code du contrôleur — c'est le principe d'inversion de dépendances.

Afficher plusieurs graphiques

Afficher plusieurs graphiques sur une même page

Il est tout à fait possible d'afficher plusieurs graphiques sur une même page. Il suffit de créer plusieurs objets Chart dans le contrôleur et de les passer tous au template :

$chartVentes = $chartBuilder->createChart(Chart::TYPE_BAR);
$chartVisites = $chartBuilder->createChart(Chart::TYPE_LINE);

return $this->render('statistique/index.html.twig', [
'chartVentes' => $chartVentes,
'chartVisites' => $chartVisites,
]);

Dans Twig :

{{ render_chart(chartVentes) }}
{{ render_chart(chartVisites) }}

Chaque appel à render_chart() génère une balise <canvas> indépendante, et Stimulus instancie Chart.js séparément pour chacune.


Exemple pratique

Création d'un graphique de ventes

Cet exemple montre comment créer un graphique en barres affichant des ventes mensuelles fictives dans un projet Symfony avec ux-chartjs déjà installé.

info

Si ux-chartjs n'est pas encore installé, exécuter dans le terminal : composer require symfony/ux-chartjs

Étape 1 — Créer le contrôleur

Dans le terminal VS Code, générer un nouveau contrôleur :

php bin/console make:controller StatistiqueController

Ouvrir le fichier généré src/Controller/StatistiqueController.php et le remplacer par le code suivant :

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

class StatistiqueController extends AbstractController
{
#[Route('/statistiques', name: 'app_statistiques')]
public function index(ChartBuilderInterface $chartBuilder): Response
{
// Création d'un graphique en barres
$chart = $chartBuilder->createChart(Chart::TYPE_BAR);

// Définition des données
$chart->setData([
'labels' => [
'Janvier', 'Février', 'Mars', 'Avril',
'Mai', 'Juin', 'Juillet', 'Août',
'Septembre', 'Octobre', 'Novembre', 'Décembre'
],
'datasets' => [
[
'label' => 'Ventes 2024 (en €)',
'data' => [4200, 3800, 5100, 4700, 6200, 5800, 7100, 6500, 5900, 6800, 7400, 8200],
'backgroundColor' => 'rgba(54, 162, 235, 0.6)',
'borderColor' => 'rgb(54, 162, 235)',
'borderWidth' => 2,
],
],
]);

// Options de configuration
$chart->setOptions([
'responsive' => true,
'plugins' => [
'legend' => ['position' => 'top'],
'title' => [
'display' => true,
'text' => 'Chiffre d\'affaires mensuel 2024',
],
],
'scales' => [
'y' => ['beginAtZero' => true],
],
]);

return $this->render('statistique/index.html.twig', [
'chart' => $chart,
]);
}
}

Étape 2 — Créer le template Twig

Ouvrir le fichier templates/statistique/index.html.twig généré automatiquement et le remplacer par :

{% extends 'base.html.twig' %}

{% block title %}Statistiques de ventes{% endblock %}

{% block body %}
<div style="max-width: 900px; margin: 2rem auto; padding: 0 1rem;">
<h1>Statistiques de ventes 2024</h1>
<p>Voici l'évolution du chiffre d'affaires mois par mois.</p>

{{ render_chart(chart) }}
</div>
{% endblock %}

Étape 3 — Vérifier base.html.twig

Ouvrir templates/base.html.twig et s'assurer que la balise suivante est présente dans le <head> :

{{ importmap('app') }}

Étape 4 — Lancer le serveur et tester

symfony server:start

Ouvrir https://127.0.0.1:8000/statistiques dans le navigateur. Un graphique en barres bleutées doit s'afficher avec les 12 mois de l'année en abscisse et les valeurs de ventes en ordonnée.

Étape 5 — Ajouter une deuxième série de données

Pour comparer deux années, modifier la méthode setData() dans le contrôleur en ajoutant un second dataset :

'datasets' => [
[
'label' => 'Ventes 2023 (en €)',
'data' => [3800, 3200, 4500, 4100, 5600, 5000, 6400, 5900, 5200, 6100, 6700, 7500],
'backgroundColor' => 'rgba(255, 99, 132, 0.6)',
'borderColor' => 'rgb(255, 99, 132)',
'borderWidth' => 2,
],
[
'label' => 'Ventes 2024 (en €)',
'data' => [4200, 3800, 5100, 4700, 6200, 5800, 7100, 6500, 5900, 6800, 7400, 8200],
'backgroundColor' => 'rgba(54, 162, 235, 0.6)',
'borderColor' => 'rgb(54, 162, 235)',
'borderWidth' => 2,
],
],

Rafraîchir la page : le graphique affiche maintenant deux séries de barres côte à côte, avec une légende différenciant 2023 (rouge) et 2024 (bleu).

astuce

Aucune modification du template Twig n'est nécessaire pour ajouter une série : tout se gère côté PHP dans le contrôleur. C'est tout l'intérêt de ux-chartjs.


Test de mémorisation/compréhension


Quelle interface Symfony doit-on injecter dans un contrôleur pour créer un graphique avec ux-chartjs ?


Quelle constante PHP correspond à un graphique en camembert ?


Que contient obligatoirement la clé `labels` dans `setData()` ?


Quelle fonction Twig génère la balise HTML nécessaire à l'affichage du graphique ?


Que se passe-t-il si `{{ importmap('app') }}` est absent de `base.html.twig` ?


Dans un dataset Chart.js, quelle clé définit les valeurs numériques à afficher ?


Quelle option Chart.js force l'axe Y à commencer à zéro ?


Comment afficher deux graphiques différents sur une même page Twig ?


Quelle balise HTML `render_chart()` génère-t-elle dans la page ?


Pourquoi utilise-t-on `ChartBuilderInterface` plutôt que d'instancier `Chart` directement avec `new Chart()` ?



TP pour réfléchir et résoudre des problèmes

Dans ce TP, vous allez créer un tableau de bord de statistiques fictives pour une boutique en ligne, en affichant 2 graphiques distincts sur une même page :

  • un graphique en barres pour les ventes mensuelles
  • et un graphique en courbes pour le nombre de visiteurs.

Tout le travail se fait côté PHP et Twig, sans écrire une seule ligne de JavaScript.


Étape 1 — Préparer le projet

Ouvrez un terminal PowerShell ou le terminal intégré de VS Code (Ctrl + ù), naviguez vers votre dossier Documents et créez un nouveau projet Symfony :

cd %USERPROFILE%\Documents
symfony new tp-chartjs --webapp
cd tp-chartjs
code .

Une fois VS Code ouvert sur le projet, installez le composant ux-chartjs :

composer require symfony/ux-chartjs

Vérifiez ensuite que assets/controllers.json contient bien l'entrée pour @symfony/ux-chartjs.

Une solution

Étape 2 — Vérifier la balise importmap dans base.html.twig

Avant de créer le moindre contrôleur, ouvrez le fichier templates/base.html.twig et localisez la balise <head>. Vérifiez que la ligne suivante est bien présente :

{{ importmap('app') }}

Si elle est absente, ajoutez-la manuellement avant la balise fermante </head>.

Une solution

Étape 3 — Créer le contrôleur DashboardController

Dans le terminal, générez un contrôleur nommé DashboardController :

php bin/console make:controller DashboardController

Deux fichiers sont créés :

  • src/Controller/DashboardController.php
  • templates/dashboard/index.html.twig

Ouvrez src/Controller/DashboardController.php et remplacez intégralement son contenu par le code suivant, qui crée un premier graphique en barres pour les ventes mensuelles :

<?php

namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
use Symfony\UX\Chartjs\Builder\ChartBuilderInterface;
use Symfony\UX\Chartjs\Model\Chart;

class DashboardController extends AbstractController
{
#[Route('/dashboard', name: 'app_dashboard')]
public function index(ChartBuilderInterface $chartBuilder): Response
{
$chartVentes = $chartBuilder->createChart(Chart::TYPE_BAR);

$chartVentes->setData([
'labels' => [
'Janvier', 'Février', 'Mars', 'Avril',
'Mai', 'Juin', 'Juillet', 'Août',
'Septembre', 'Octobre', 'Novembre', 'Décembre',
],
'datasets' => [
[
'label' => 'Ventes (en €)',
'data' => [3200, 2800, 4100, 3700, 5200, 4900, 6100, 5500, 4800, 5700, 6300, 7100],
'backgroundColor' => 'rgba(75, 192, 192, 0.6)',
'borderColor' => 'rgb(75, 192, 192)',
'borderWidth' => 2,
],
],
]);

$chartVentes->setOptions([
'responsive' => true,
'plugins' => [
'legend' => ['position' => 'top'],
'title' => [
'display' => true,
'text' => 'Ventes mensuelles de la boutique',
],
],
'scales' => [
'y' => ['beginAtZero' => true],
],
]);

return $this->render('dashboard/index.html.twig', [
'chartVentes' => $chartVentes,
]);
}
}
Une solution

Étape 4 — Créer le template Twig du dashboard

Ouvrez templates/dashboard/index.html.twig et remplacez son contenu par :

{% extends 'base.html.twig' %}

{% block title %}Tableau de bord{% endblock %}

{% block body %}
<div style="max-width: 960px; margin: 2rem auto; padding: 0 1rem;">
<h1>Tableau de bord — boutique en ligne</h1>

<section style="margin-top: 2rem;">
<h2>Ventes mensuelles</h2>
{{ render_chart(chartVentes) }}
</section>
</div>
{% endblock %}

Lancez ensuite le serveur de développement et vérifiez l'affichage :

symfony server:start

Ouvrez https://127.0.0.1:8000/dashboard dans le navigateur. Le graphique en barres doit s'afficher avec les 12 mois et les valeurs de ventes.

Une solution

Étape 5 — Ajouter un second graphique en courbes pour les visiteurs

Modifiez le contrôleur DashboardController.php pour créer un second graphique de type LINE, représentant le nombre de visiteurs mensuels. Transmettez ce second graphique au template.

Le second graphique doit :

  • Être de type courbe (Chart::TYPE_LINE)
  • Avoir les mêmes 12 mois en labels
  • Contenir les données suivantes : [1200, 980, 1450, 1320, 1800, 1650, 2100, 1950, 1700, 2050, 2300, 2700]
  • Utiliser la couleur rgba(255, 159, 64, 0.6) pour le fond et rgb(255, 159, 64) pour la bordure
  • Avoir un titre : Visiteurs mensuels de la boutique
Une solution

Étape 6 — Afficher le second graphique dans le template

Modifiez templates/dashboard/index.html.twig pour afficher le second graphique sous le premier, dans une nouvelle section avec son propre titre.

Une solution

Étape 7 — Ajouter une comparaison sur le graphique des ventes

Modifiez uniquement la partie $chartVentes du contrôleur pour ajouter une seconde série représentant les ventes de l'année précédente, avec les données suivantes :

  • Label : Ventes 2023 (en €)
  • Données : [2800, 2400, 3600, 3200, 4500, 4100, 5300, 4800, 4200, 5000, 5600, 6400]
  • Couleur de fond : rgba(255, 99, 132, 0.6)
  • Couleur de bordure : rgb(255, 99, 132)

Le template Twig n'a pas besoin d'être modifié.

Une solution